{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Linking Plots Using Fast Interval Selector"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Details on how to use the fast interval selector can be found in [this](../Interactions/Selectors.ipynb#fastintervalselector) notebook. In this tutorial notebook, we will look at linking plots using the fast interval selector. Interval selectors are ideally suited for time series analysis where we want to perform statistical computations on different time periods.\n",
    "\n",
    "When creating an interval selector we need pass in the x scale. We can additionally pass in the marks on which the interval selector operates. When the interval selector moves, it updates the following traits (on which callbacks can be registered)\n",
    "* `selected` trait of the interval selector object itself. This trait contains the start and end of the x axis obtained from the x scale. Note that these values may not be present in the `x` attribute of the marks!\n",
    "* `selected` trait of the marks on which the selector operates. This trait contains *all* the *indices* of the line.x which are spanned by the interval selector.\n",
    "\n",
    "The recipe for linking plots is as follows:\n",
    "\n",
    "1. Create an interval selector object by passing in the X-scale and marks on which the selector should operate on (optional)\n",
    "2. Pass it to the figure through the `interaction` argument\n",
    "3. Register a callback (which potentially updates other plots) on either the `selected` attribute of the interval selector object or `selected` attribute of the marks objects in the figure\n",
    "\n",
    "<br>`FastIntervalSelector` updates the `selected` trait **continuously**. Therefore, registering computationally intensive callbacks is *not* recommended with `FastIntervalSelector`\n",
    "\n",
    "Let's now look at an example of linking a time series plot to a scatter plot using a `FastIntervalSelector`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from ipywidgets import Layout, HTML, VBox\n",
    "import bqplot.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's set up an interval selector on a figure containing two time series plots. The interval selector can be activated by clicking on the figure"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from bqplot.interacts import FastIntervalSelector\n",
    "\n",
    "y1, y2 = np.random.randn(2, 200).cumsum(axis=1) # two simple random walks\n",
    "\n",
    "fig_layout = Layout(width='900px', height='500px')\n",
    "time_series_fig = plt.figure(layout=fig_layout)\n",
    "line = plt.plot([y1, y2])\n",
    "\n",
    "# create a fast interval selector by passing in the X scale and the line mark on which the selector operates\n",
    "intsel = FastIntervalSelector(marks=[line], scale=line.scales['x'])\n",
    "time_series_fig.interaction = intsel # set the interval selector on the figure"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's now create a scatter plot of the two time series and stack it below the time series plot using a `VBox`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scat_fig = plt.figure(layout=fig_layout, title='Scatter of time series slice selected by the interval selector')\n",
    "# set the x and y attributes to the y values of line.y\n",
    "scat = plt.scatter(*line.y, colors=['red'], stroke='black') "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# define a callback for the interval selector\n",
    "def update_scatter(*args):\n",
    "    # get the start and end indices of the interval\n",
    "    start_ix, end_ix = line.selected[0], line.selected[-1]\n",
    "    \n",
    "    #update the x and y attributes of the scatter by slicing line.y\n",
    "    with scat.hold_sync():\n",
    "        scat.x, scat.y = line.y[:, start_ix:end_ix]\n",
    "\n",
    "# register the callback with line.selected trait\n",
    "line.observe(update_scatter, 'selected')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "help_label = HTML('<div style=\"color: blue; font-size: 16px; margin:20px 0px 0px 50px\">\\\n",
    "                  Click on the time series plot to activate the interval selector</div>')\n",
    "VBox([help_label, time_series_fig, scat_fig])"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
